// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "DBManager/Repository/HDF5/Input/Constraint/RBE3Repository.h"

#include "DBManager/Repository/HDF5/Base/HDF5RepositoryMacro.h"

#include "RBE3Repository.h"

HDF5_REG_REPOSITORY (RBE3Repository)

using namespace SG::DBManager::HDF5;
using namespace SG::DBManager::HDF5::RBE3;
using namespace SG::DataStructure::FEM;
using namespace SG::DataStructure::Common;

// 构造函数实现
RBE3Repository::RBE3Repository (HDF5Database& database) : SG::DBManager::HDF5::MainlyRepositoryBase<RBE3Data> (database)
{}

void RBE3Repository::InitialDatasetInfo ()
{
    RegisterIndex ("/OWN/INDEX/INPUT/ELEMENT/RBE3", IndexDataset, GetType ());
    RegisterTableInfo<IDENTITY> ("/SG/INPUT/ELEMENT/RBE3/IDENTITY", MainDataset);
    RegisterTableInfo<WTCG> ("/SG/INPUT/ELEMENT/RBE3/WTCG", SubDatasetWTCG);
    RegisterTableInfo<RBE3Data::GM> ("/SG/INPUT/ELEMENT/RBE3/GM", SubDatasetGM);
    RegisterTableInfo<SG::DBManager::HDF5::RBE3::G> ("/SG/INPUT/ELEMENT/RBE3/G", G);

    // 连接信号槽 当调用汇总的时候，将已有的缓存信息全部都持久化到HDF5文件中。
    GetDatabase ().GetHDF5Hub ()->m_rElementSummarySignal.connect ([this] { Sort (); });
}
void RBE3Repository::DumpWriteCahce ()
{
    auto& writeStorage = this->GetMainCache ().m_writeStorage;

    // 1. flag设置为无顺序
    GetMainDatasetInfo ().SetIsSequential (false);

    // 主表数据
    std::vector<IDENTITY> IDENTITYData{};
    // 附表数据
    std::vector<WTCG>         wtcgData;
    std::vector<RBE3Data::GM> gmData;
    // 附表の附表数据
    std::vector<SG::DBManager::HDF5::RBE3::G> gData;

    // 2. convert to nastran format
    OwnToNastran (writeStorage, IDENTITYData, wtcgData, gmData, gData);

    // 3. 写出数据至文件
    WriteData (MainDataset, IDENTITYData);
    WriteData (SubDatasetWTCG, wtcgData);
    WriteData (SubDatasetGM, gmData);
    WriteData (G, gData);

    writeStorage.clear ();
}
std::vector<RBE3Repository::DataType>*  RBE3Repository::LoadReadCache (std::size_t loadIndex)
{
    // 1. 读取范围内主表数据
    std::vector<IDENTITY> IDENTITYData;
    LoadMainMetadata (loadIndex, IDENTITYData);

    if (IDENTITYData.empty ())
        return nullptr;

    // 2. 读取范围内附表数据
    std::vector<RBE3Data::GM> gmData;
    LoadSecondaryMetadata (IDENTITYData, GM_POS, GM_LEN, SubDatasetGM, gmData);

    std::vector<RBE3::WTCG> wtcgData;
    LoadSecondaryMetadata (IDENTITYData, WTCG_POS, WTCG_LEN, SubDatasetWTCG, wtcgData);

    std::vector<SG::DBManager::HDF5::RBE3::G> gData;
    LoadSecondaryMetadata (wtcgData, G_POS, G_LEN, G, gData);

    // 3. 将数据转换为自己的格式放入缓存
    auto* cacheVector = m_cacheHelper.LookupOrCreateVector<DataType> (GetMainCache ().m_readCacheKey, IDENTITYData.size ());
    NastranToOwn (IDENTITYData, wtcgData, gmData, gData, *cacheVector);
    return cacheVector;
}

void RBE3Repository::SortData ()  // NOLINT(readability-function-cognitive-complexity)
{
    // 1. 读取主表数据
    std::vector<IDENTITY> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        GetMainDatasetInfo ().SetIsSequential (true);
        return;
    }

    // 2. 读取附表数据
    std::vector<RBE3Data::GM> gmData;
    GetDataset (SubDatasetGM).read (gmData);
    std::vector<WTCG> wtcgData;
    GetDataset (SubDatasetWTCG).read (wtcgData);
    std::vector<SG::DBManager::HDF5::RBE3::G> gData;
    GetDataset (G).read (gData);

    // 3. 将所有数据转换
    std::vector<RBE3Data> AllData{};
    NastranToOwn (IDENTITYData, wtcgData, gmData, gData, AllData);

    // 4. 排序
    std::sort (AllData.begin (), AllData.end ());

    // 5. 转换回nastran格式
    OwnToNastran (AllData, IDENTITYData, wtcgData, gmData, gData, true);

    // 6. 写出主表数据至文件
    GetDataset (MainDataset).write (IDENTITYData);
    // 7. 写出附表数据至文件
    GetDataset (SubDatasetGM).write (gmData);
    GetDataset (SubDatasetWTCG).write (wtcgData);
    GetDataset (G).write (gData);

    // 8. 重写索引
    RewriteIndexData (AllData);

    // 9. 设置为已顺序
    GetMainDatasetInfo ().SetIsSequential (true);
}
std::vector<SG::DataStructure::FEM::RBE3Data> RBE3Repository::GetAllData ()
{
    Sort ();

    std::vector<SG::DataStructure::FEM::RBE3Data> result;

    // 1. 读取主表数据
    std::vector<IDENTITY> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        return result;
    }

    // 2. 读取附表数据
    std::vector<RBE3Data::GM> gmData;
    GetDataset (SubDatasetGM).read (gmData);
    std::vector<WTCG> wtcgData;
    GetDataset (SubDatasetWTCG).read (wtcgData);
    std::vector<SG::DBManager::HDF5::RBE3::G> gData;
    GetDataset (G).read (gData);

    // 3. 将所有数据转换
    NastranToOwn (IDENTITYData, wtcgData, gmData, gData, result);

    return result;
}
void RBE3Repository::OwnToNastran (std::vector<SG::DataStructure::FEM::RBE3Data>&          own,
                                   std::vector<SG::DBManager::HDF5::RBE3::IDENTITY>& _OUT  IDENTITYData,
                                   std::vector<SG::DBManager::HDF5::RBE3::WTCG>& _OUT      wtcgData,
                                   std::vector<SG::DataStructure::FEM::RBE3Data::GM>& _OUT gmData,
                                   std::vector<SG::DBManager::HDF5::RBE3::G>& _OUT         gData,
                                   bool                                                    isSort)
{
    wtcgData.clear ();
    gmData.clear ();
    gData.clear ();
    IDENTITYData.clear ();
    IDENTITYData.reserve (own.size ());

    // 获取已有数据条数，主要是放在主表的POS字段
    // 如果是重新排序的时候，Pos都是从0 开始的
    size_t wtcgCount = isSort ? 0 : this->GetDatasetInfo (SubDatasetWTCG).GetRowCount ();
    size_t gmCount   = isSort ? 0 : this->GetDatasetInfo (SubDatasetGM).GetRowCount ();
    size_t gCount    = isSort ? 0 : this->GetDatasetInfo (G).GetRowCount ();

    // OwnIdent 代表咱们自己的数据结构
    // NasIdent 代表nastran的数据结构
    for (auto& OwnIdent : own)
    {
        // 写入附表GM
        gmData.insert (gmData.end (), OwnIdent.m_GM.begin (), OwnIdent.m_GM.end ());

        // 写入附表WTCG
        for (auto&& wtcg : OwnIdent.m_WTCG)
        {
            wtcgData.emplace_back (wtcg.m_wt1, wtcg.m_c, gCount, wtcg.m_g.size ());

            // 写入附表の附表G
            for (auto&& i : wtcg.m_g)
            {
                gData.emplace_back (i);
            }

            gCount += wtcg.m_g.size ();
        }

        const size_t wtcgLen = OwnIdent.m_WTCG.size ();
        const size_t gmLen   = OwnIdent.m_GM.size ();

        // 写入IDENTITY
        IDENTITY NasIdent{};
        NasIdent.EID       = OwnIdent.m_id;
        NasIdent.REFG      = OwnIdent.m_refg;
        NasIdent.REFC      = OwnIdent.m_refc;
        NasIdent.WTCG_POS  = static_cast<I64> (wtcgCount);
        NasIdent.WTCG_LEN  = static_cast<I64> (wtcgLen);
        NasIdent.GM_POS    = static_cast<I64> (gmCount);
        NasIdent.GM_LEN    = static_cast<I64> (gmLen);
        NasIdent.ALPHA     = OwnIdent.m_alpha;
        NasIdent.TREF      = OwnIdent.m_tref;
        NasIdent.DOMAIN_ID = OwnIdent.m_domainId;

        IDENTITYData.emplace_back (NasIdent);

        wtcgCount += wtcgLen;
        gmCount += gmLen;
    }
}

void RBE3Repository::NastranToOwn (std::vector<SG::DBManager::HDF5::RBE3::IDENTITY>&   IDENTITYData,
                                   std::vector<SG::DBManager::HDF5::RBE3::WTCG>&       wtcgData,
                                   std::vector<SG::DataStructure::FEM::RBE3Data::GM>&  gmData,
                                   std::vector<SG::DBManager::HDF5::RBE3::G>&          gData,
                                   std::vector<SG::DataStructure::FEM::RBE3Data>& _OUT own)
{
    own.clear ();
    own.reserve (IDENTITYData.size ());

    // 代表初始的Index 位置, 因为数据有可能是截取了附表的一部分，所有主表中根据POS找的时候需要对应一下，
    // 比如第一个主表数据中POS字段为10000， 附表的vector的数据 就是从附表中的第10000个开始对应的 也就是Index==0的
    const I64 wtcgIndex = IDENTITYData[0].WTCG_POS;
    const I64 gmIndex   = IDENTITYData[0].GM_POS;
    const I64 gIndex    = wtcgData.size () > 0 ? wtcgData[0].G_POS : 0;

    RBE3Data const tempown;
    own.resize (IDENTITYData.size (), tempown);

    for (size_t i = 0; i < IDENTITYData.size (); i++)
    {
        auto& OwnIdent = own[i];
        auto& NasIdent = IDENTITYData[i];

        OwnIdent.m_id       = NasIdent.EID;
        OwnIdent.m_refg     = NasIdent.REFG;
        OwnIdent.m_refc     = NasIdent.REFC;
        OwnIdent.m_alpha    = NasIdent.ALPHA;
        OwnIdent.m_tref     = NasIdent.TREF;
        OwnIdent.m_domainId = NasIdent.DOMAIN_ID;

        if (NasIdent.GM_LEN != 0)
        {
            OwnIdent.m_GM.assign (gmData.begin () + NasIdent.GM_POS - gmIndex,
                                  gmData.begin () + NasIdent.GM_POS + NasIdent.GM_LEN - gmIndex);
        }

        if (NasIdent.WTCG_LEN != 0)
        {
            // 范围内WTCG数据
            std::vector<SG::DBManager::HDF5::RBE3::WTCG> NasWTCGList (
                wtcgData.begin () + NasIdent.WTCG_POS - wtcgIndex, wtcgData.begin () + NasIdent.WTCG_POS + NasIdent.WTCG_LEN - wtcgIndex);

            OwnIdent.m_WTCG.resize (NasWTCGList.size ());

            for (size_t i = 0; i < NasWTCGList.size (); i++)
            {
                OwnIdent.m_WTCG[i].m_wt1 = NasWTCGList[i].WT1;
                OwnIdent.m_WTCG[i].m_c   = NasWTCGList[i].C;
                // OwnIdent.m_WTCG[i].m_g.assign (gData.begin () + NasWTCGList[i].G_POS - gIndex,
                //                                gData.begin () + NasWTCGList[i].G_POS + NasWTCGList[i].G_LEN - gIndex);
                // 使用循环方式添加到m_g
                OwnIdent.m_WTCG[i].m_g.reserve (NasWTCGList[i].G_LEN);
                for (SG::DataStructure::Common::I64 j = 0; j < NasWTCGList[i].G_LEN; j++)
                {
                    OwnIdent.m_WTCG[i].m_g.push_back (gData[NasWTCGList[i].G_POS - gIndex + j].ID);
                }
            }
        }
    }
}
